/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvyh.lightframe.core.invoke.request;

import com.lvyh.lightframe.core.config.ReferenceConfig;
import com.lvyh.lightframe.core.invoke.response.ResponseCallback;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lvyh 2021/05/23.
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RpcRequest implements Serializable {
    private static final long serialVersionUID = 50L;

    private String requestId;
    private long createMillisTime;
    private String serverAddress;
    private String className;
    private String methodName;
    private Class<?>[] parameterTypes;
    private String[] parameterTypesValue;
    private Object[] parameters;

    private String invokeType;
    private ResponseCallback responseCallback;
    private long timeout;
    private String version;
    private String directIp;
    private String transport;
    private String loadBalance;
    private boolean generic;

    private ReferenceConfig referenceConfig;

    /**
     * Extensional properties of request
     */
    private Map<String, Object> attachment;

    /**
     * Gets request prop.
     */
    public Object getAttachment(String key) {
        return attachment != null ? attachment.get(key) : null;
    }

    /**
     * Add request prop.
     */
    public void addAttachment(String key, Object value) {
        if (key == null || value == null) {
            return;
        }
        if (attachment == null) {
            attachment = new HashMap<String, Object>(16);
        }
        attachment.put(key, value);
    }

    /**
     * Remove request prop.
     */
    public void removeAttachment(String key) {
        if (key == null) {
            return;
        }
        if (attachment != null) {
            attachment.remove(key);
        }
    }

    /**
     * Add request props.
     */
    public void addAttachment(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return;
        }
        if (attachment == null) {
            attachment = new HashMap<String, Object>(16);
        }
        attachment.putAll(map);
    }

    /**
     * Gets request props.
     */
    public Map<String, Object> getAttachment() {
        return attachment;
    }

    public RpcRequest(String requestId) {
        this.requestId = requestId;
    }

    public String getServiceKey() {
        String inf = this.getClassName();
        if (inf == null) return null;
        StringBuilder buf = new StringBuilder();
        String group = "";
        if (group != null && group.length() > 0) {
            buf.append(group).append("/");
        }
        buf.append(inf);
        String version = this.getVersion();
        if (version != null && version.length() > 0) {
            buf.append(":").append(version);
        }
        return buf.toString();
    }


    public static class Builder {
        private RpcRequest instance;

        public Builder(RpcRequest q) {
            this.instance = q;
        }

        public Builder() {
            this(new RpcRequest());
        }

        public Builder setRequestId(String requestId) {
            this.instance.requestId = requestId;
            return this;
        }

        public Builder setCreateMillisTime(long createMillisTime) {
            this.instance.createMillisTime = createMillisTime;
            return this;
        }


        public Builder setServerAddress(String serverAddress) {
            this.instance.serverAddress = serverAddress;
            return this;
        }

        public Builder setClassName(String className) {
            this.instance.className = className;
            return this;
        }

        public Builder setMethodName(String methodName) {
            this.instance.methodName = methodName;
            return this;
        }

        public Builder setParameterTypes(Class<?>[] parameterTypes) {
            this.instance.parameterTypes = parameterTypes;
            return this;
        }

        public Builder setParameterTypesValue(String[] parameterTypesValue) {
            this.instance.parameterTypesValue = parameterTypesValue;
            return this;
        }

        public Builder setParameters(Object[] parameters) {
            this.instance.parameters = parameters;
            return this;
        }

        public Builder setInvokeType(String invokeType) {
            this.instance.invokeType = invokeType;
            return this;
        }

        public Builder setResponseCallback(ResponseCallback responseCallback) {
            this.instance.responseCallback = responseCallback;
            return this;
        }

        public Builder setTimeout(long timeout) {
            this.instance.timeout = timeout;
            return this;
        }

        public Builder setVersion(String version) {
            this.instance.version = version;
            return this;
        }

        public Builder setDirectIp(String directIp) {
            this.instance.directIp = directIp;
            return this;
        }


        public Builder setTransport(String transport) {
            this.instance.transport = transport;
            return this;
        }

        public Builder setLoadBalance(String loadBalance) {
            this.instance.loadBalance = loadBalance;
            return this;
        }

        public Builder setGeneric(boolean generic) {
            this.instance.generic = generic;
            return this;
        }

        public Builder setReferenceConfig(ReferenceConfig referenceConfig) {
            this.instance.referenceConfig = referenceConfig;
            return this;
        }

        public Builder setAttachment(Map<String, Object> attachment) {
            this.instance.attachment = attachment;
            return this;
        }

        public RpcRequest build() {
            return this.instance;
        }
    }

}
